"""
任务管理服务
"""

from typing import  Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, desc, func

from models.task import Task, TaskDependency
from models.execution import Execution
from models.repository import Repository
from schemas.task import TaskCreate, TaskUpdate, TaskListResponse
from utils.logger import get_logger

logger = get_logger(__name__)


class TaskService:
    """任务管理服务"""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def create_task(self, task_data: TaskCreate) -> Task:
        """创建新任务"""
        try:
            # 验证源代码库是否存在
            source_repo = await self.db.get(Repository, task_data.source_repo_id)
            if not source_repo:
                raise ValueError("源代码库不存在")

            # 创建任务
            task = Task(
                name=task_data.name,
                description=task_data.description,
                source_repo_id=task_data.source_repo_id,
                target_repos=task_data.target_repos,
                branch_mapping=task_data.branch_mapping,
                schedule_config=task_data.schedule_config,
                files=task_data.files,
                force_push=task_data.force_push,
                max_concurrent=task_data.max_concurrent,
                retry_count=task_data.retry_count,
                timeout_seconds=task_data.timeout_seconds,
                is_active=task_data.is_active,
            )

            self.db.add(task)
            await self.db.commit()
            await self.db.refresh(task)

            logger.info("任务创建成功", task_id=task.id, task_name=task.name)
            return task

        except Exception as e:
            await self.db.rollback()
            logger.error("任务创建失败", error=str(e))
            raise

    async def get_task(self, task_id: int) -> Optional[Task]:
        """获取任务详情"""
        try:
            stmt = select(Task).where(Task.id == task_id)
            result = await self.db.execute(stmt)
            task = result.scalar_one_or_none()

            if task:
                logger.debug("获取任务成功", task_id=task_id)
            else:
                logger.warning("任务不存在", task_id=task_id)

            return task

        except Exception as e:
            logger.error("获取任务失败", task_id=task_id, error=str(e))
            raise

    async def get_tasks(
        self,
        page: int = 1,
        size: int = 10,
        status: Optional[str] = None,
        search: Optional[str] = None
    ) -> TaskListResponse:
        """获取任务列表"""
        try:
            # 构建查询条件
            conditions = []

            if status:
                conditions.append(Task.status == status)

            if search:
                conditions.append(
                    or_(
                        Task.name.ilike(f"%{search}%"),
                        Task.description.ilike(f"%{search}%")
                    )
                )

            # 查询总数
            count_stmt = select(func.count(Task.id))
            if conditions:
                count_stmt = count_stmt.where(and_(*conditions))

            total_result = await self.db.execute(count_stmt)
            total = total_result.scalar()

            # 查询数据
            stmt = select(Task)
            if conditions:
                stmt = stmt.where(and_(*conditions))

            stmt = stmt.order_by(desc(Task.updated_at))
            stmt = stmt.offset((page - 1) * size).limit(size)

            result = await self.db.execute(stmt)
            tasks = result.scalars().all()

            logger.info(
                "获取任务列表成功",
                page=page,
                size=size,
                total=total,
                actual_count=len(tasks)
            )

            return TaskListResponse(
                total=total,
                page=page,
                size=size,
                items=tasks
            )

        except Exception as e:
            logger.error("获取任务列表失败", error=str(e))
            raise

    async def update_task(self, task_id: int, task_data: TaskUpdate) -> Optional[Task]:
        """更新任务"""
        try:
            task = await self.get_task(task_id)
            if not task:
                return None

            # 更新字段
            update_data = task_data.dict(exclude_unset=True)
            for field, value in update_data.items():
                setattr(task, field, value)

            await self.db.commit()
            await self.db.refresh(task)

            logger.info("任务更新成功", task_id=task_id)
            return task

        except Exception as e:
            await self.db.rollback()
            logger.error("任务更新失败", task_id=task_id, error=str(e))
            raise

    async def delete_task(self, task_id: int) -> bool:
        """删除任务"""
        try:
            task = await self.get_task(task_id)
            if not task:
                return False

            await self.db.delete(task)
            await self.db.commit()

            logger.info("任务删除成功", task_id=task_id)
            return True

        except Exception as e:
            await self.db.rollback()
            logger.error("任务删除失败", task_id=task_id, error=str(e))
            raise

    async def execute_task(self, task_id: int) -> Optional[Execution]:
        """执行任务"""
        try:
            task = await self.get_task(task_id)
            if not task:
                return None

            if not task.is_active:
                raise ValueError("任务未激活")

            # 创建执行记录
            execution = Execution(
                task_id=task_id,
                status="pending",
                triggered_by="manual",
                source_commit="",  # 将在执行过程中填充
                branch_mapping=task.branch_mapping,
            )

            self.db.add(execution)
            await self.db.commit()
            await self.db.refresh(execution)

            # TODO: 启动异步任务执行
            # 这里应该调用Celery任务来执行实际的同步操作

            logger.info("任务执行启动", task_id=task_id, execution_id=execution.id)
            return execution

        except Exception as e:
            await self.db.rollback()
            logger.error("任务执行失败", task_id=task_id, error=str(e))
            raise

    async def get_task_executions(self, task_id: int, limit: int = 10) -> List[Execution]:
        """获取任务执行历史"""
        try:
            stmt = select(Execution).where(
                Execution.task_id == task_id
            ).order_by(desc(Execution.created_at)).limit(limit)

            result = await self.db.execute(stmt)
            executions = result.scalars().all()

            logger.debug("获取任务执行历史成功", task_id=task_id, count=len(executions))
            return executions

        except Exception as e:
            logger.error("获取任务执行历史失败", task_id=task_id, error=str(e))
            raise

    async def validate_task_config(self, task_data: TaskCreate) -> Dict[str, Any]:
        """验证任务配置"""
        try:
            errors = []
            warnings = []

            # 验证源代码库
            source_repo = await self.db.get(Repository, task_data.source_repo_id)
            if not source_repo:
                errors.append("源代码库不存在")
            elif not source_repo.is_source:
                warnings.append("源代码库未标记为源库")

            # 验证目标代码库
            if not task_data.target_repos:
                errors.append("至少需要一个目标代码库")
            else:
                target_repo_ids = [repo.get("id") for repo in task_data.target_repos if repo.get("id")]
                for repo_id in target_repo_ids:
                    target_repo = await self.db.get(Repository, repo_id)
                    if not target_repo:
                        errors.append(f"目标代码库 {repo_id} 不存在")

            # 验证分支映射
            if not task_data.branch_mapping:
                errors.append("分支映射配置不能为空")
            else:
                source_branch = task_data.branch_mapping.get("source_branch")
                if not source_branch:
                    errors.append("源分支不能为空")

            return {
                "valid": len(errors) == 0,
                "errors": errors,
                "warnings": warnings
            }

        except Exception as e:
            logger.error("任务配置验证失败", error=str(e))
            return {
                "valid": False,
                "errors": [f"验证过程中发生错误: {str(e)}"],
                "warnings": []
            }